package Objects;

import GameEngine.GameConstants;
import GameEngine.GameConstants.Action;
import GameEngine.GameConstants.Effect;
import GameEngine.GameConstants.Graphic;
import GameEngine.GameConstants.Material;
import GameEngine.GameConstants.Modifier;
import GameEngine.GameConstants.Special;
import GameEngine.GameConstants.Thing;
import GameEngine.Group;
import GameEngine.Vector;
import java.util.List;

/**
 * This will represent an actual character.
 * @author mhfowler
 */
public class Player extends GameObject {


    /* what kind of player */
    Special type;

    /* for powers */
    Group g;

    /* what is your velocity from user actions */
    Vector movement;
    boolean landed = false; // determines if the player can jump
    boolean nextLanded = false;

    public Player(SpawnPoint spawnPoint) {
        super(spawnPoint.getDir(), spawnPoint.getCenter(), spawnPoint.getSize(), Graphic.PINKPLAYER_WALK);
        material = Material.PLAYER;
        movement = new Vector(0, 0);
        acceleration = new Vector(0, GameConstants.GRAVITY_ACCELERATION);
    }

    public Player(Vector dir, Vector cen, Vector s) {
        super(dir, cen, s, Graphic.PINKPLAYER_WALK);
        material = Material.PLAYER;
        movement = new Vector(0, 0);
        acceleration = new Vector(0, GameConstants.GRAVITY_ACCELERATION);
        Group g = new Group();
    }

        /** this is the method by which other objects will effect this object. There will be a switch case
     * for each effect. For this abstract object, there will be a default implementation for each effect.
     * Specifiec objects will overwrite this method, but within them their default switch case will
     * be super.receiveEffect(), which will cause these default effects. */
    @Override
    public void receiveEffect(Effect e, Vector m, int power) {
        switch (e) {
            case DESTROY:
                lev.respawn(this);
                break;
            default:
                super.receiveEffect(e, m, power);
                break;
        }
    }

    /**
     * Mark this player as landed if they had to be offset upward
     * @param offset
     * @param totalNorm
     */
 
    @Override
    public void offset(Vector offset, float totalNorm) {
    // we can determine if a displacement was upward by
    // 1) if the displacement had a negative y component
    // 2) if the magnitude of the y component was greater than that of the x component
        super.offset(offset, totalNorm);
        if ((offset.getY() < 0) && ((Math.abs(offset.getY()) >= Math.abs(offset.getX())))) {
            nextLanded = true;
        }
    }

    /** this method will be called on both objects in a collision wherever the collision checker detects
     * a collision. By default this method will be made up of a switch case of Material, but particular
     * objects may have more interesting and nefarious collision behavior, including calling receiveEffect
     * on the object they collided with, causing an effect on their group, or causing an effect on themself.
     * @param o
     */

    @Override
    public void collide(GameObject o) {
         switch (o.material) {
            case WALL:
                 super.collide(o);
                 break;
            default:
                super.collide(o);
                break;
        }
    }

    /** this method will be called on every object at the beginning of every iteration. In this method
     * particular objects may do specific things, such as arbitrarily update their own attributes based
     * on some correlation to their lifetime (how long they've existed...eg chompers updating their deltaPosition
     * up or down), or even causing an effect on other objects. But every object must iterate through the
     * list of persistent effects on them and receive them.
     */
    @Override
    public void nextIteration() {
        velocity.scale(GameConstants.FRICTION, 1);
        velocity.add(movement);
        // deltaPosition.add(movement);
            
        /* then default */

        super.nextIteration();
        /* reset movement to nothing and onWall to false */
        movement = new Vector(0, 0);
        landed = nextLanded;
        nextLanded = false;
    }



    /* receives an action and changes himself accordingly
     * note that if a player was not colliding with a wall last turn then he cannot
     * move or jump */
    public void receiveAction(Action act) {
        switch (act) {
            case MOVELEFT:
                graph = getMoveLeft();
                if (landed) {
                    movement = new Vector(-GameConstants.MOVE_VELOCITY, 0);
                } else {
                    movement = new Vector(-GameConstants.MOVE_VELOCITY * 0.3, 0);
                }
                break;
            case MOVERIGHT:
                graph = getMoveRight();
                if (landed) {
                    movement = new Vector(GameConstants.MOVE_VELOCITY, 0);
                } else {
                    movement = new Vector(GameConstants.MOVE_VELOCITY * 0.3, 0);
                }
                break;
            case JUMP:
                graph = getJump();
                if (landed) {
                    velocity.add(new Vector(0, -GameConstants.JUMP_VELOCITY));
                //movement = onWall.getOrthog().scaleNew(GameConstants.JUMP_VELOCITY);
                }
                break;
            case USESPECIAL:
                useSpecial();
                break;
        }
    }


    public Graphic getMoveLeft() {
        Graphic toReturn = null;
        switch (type) {
            case BUILDER:
                toReturn = Graphic.GREENPLAYER_WALKLEFT;
                break;
            case EXPLODER:
                toReturn = Graphic.REDPLAYER_WALKLEFT;
                break;
            case TIME:
                toReturn = Graphic.PURPLEPLAYER_WALKLEFT;
                break;
            case TRANSMUTER:
                toReturn = Graphic.PINKPLAYER_WALKLEFT;
                break;
            }
        return toReturn;
        }

      public Graphic getMoveRight() {
        Graphic toReturn = null;
        switch (type) {
            case BUILDER:
                toReturn = Graphic.GREENPLAYER_WALK;
                break;
            case EXPLODER:
                toReturn = Graphic.REDPLAYER_WALK;
                break;
            case TIME:
                toReturn = Graphic.PURPLEPLAYER_WALK;
                break;
            case TRANSMUTER:
                toReturn = Graphic.PINKPLAYER_WALK;
                break;
            }
        return toReturn;
        }

        public Graphic getJump() {
        Graphic toReturn = null;
        switch (type) {
            case BUILDER:
                 if (graph == Graphic.GREENPLAYER_WALKLEFT || graph == Graphic.GREENPLAYER_STAYLEFT || graph == Graphic.GREENPLAYER_JUMPLEFT) {
                    toReturn = Graphic.GREENPLAYER_JUMPLEFT;
                } else {
                    toReturn = Graphic.GREENPLAYER_JUMP;
                }
                break;
            case EXPLODER:
                if (graph == Graphic.REDPLAYER_WALKLEFT || graph == Graphic.REDPLAYER_STAYLEFT || graph == Graphic.REDPLAYER_JUMPLEFT) {
                    toReturn = Graphic.REDPLAYER_JUMPLEFT;
                } else {
                    toReturn = Graphic.REDPLAYER_JUMP;
                }
                break;
            case TIME:
                if (graph == Graphic.PURPLEPLAYER_WALKLEFT || graph == Graphic.PURPLEPLAYER_STAYLEFT || graph == Graphic.PURPLEPLAYER_JUMPLEFT) {
                    toReturn = Graphic.PURPLEPLAYER_JUMPLEFT;
                } else {
                    toReturn = Graphic.PURPLEPLAYER_JUMP;
                }
                break;
            case TRANSMUTER:
                if (graph == Graphic.PINKPLAYER_WALKLEFT || graph == Graphic.PINKPLAYER_STAYLEFT || graph == Graphic.PINKPLAYER_JUMPLEFT) {
                    toReturn = Graphic.PINKPLAYER_JUMPLEFT;
                } else {
                    toReturn = Graphic.PINKPLAYER_JUMP;
                }
                break;
            }
        return toReturn;
        }



    public void setType(Special parseByteToSpecial)
    {
       type = parseByteToSpecial;

    }

    /* use special */
     public void useSpecial()
     {
         
         List<GameObject> effected = lev.within(center, new Vector (50,50));
         
         Meta toCreate = new Meta(center, size, Graphic.USESPECIAL, 15);
         lev.createObject(toCreate);

          
         switch (type) {
             case TRANSMUTER:
                 for (GameObject o : effected) {
                     if (o!=this) {
                         o.receiveEffect(Effect.TRANSMUTE, direction, 10);
                     }
                }
                 break;
             case TIME:
                 for (GameObject o : effected) {
                     if (o!=this) {
                         o.receiveEffect(Effect.PERSISTENT_SPEED, direction, 10);
                     }
                }
                 break;
             case BUILDER:
                 Wall newWall = new Wall(new Vector(0,-1), new Vector(center.getX(), center.getY()+20), new Vector(20,5));
                 lev.createObject(newWall);
                 //g.addMember(newWall);
                 break;
             case EXPLODER:
                 for (GameObject o : effected) {
                     if (o!=this) {
                         o.receiveEffect(Effect.REVERSE, center, 5);
                     }
                }
                 break;
             default:
                 System.out.println("not yet implemented");
                 break;
         }
         
       
         
     }

    




}
